import os
import random

from flask import Flask, jsonify

import asyncio
import time

from config.logger_config import logger

app = Flask(__name__)
# hypercorn --bind 0.0.0.0:5600 --workers 1 flask_async_web:asgi_app -k asyncio
from asgiref.wsgi import WsgiToAsgi
asgi_app = WsgiToAsgi(app)
global_variable = random.randint(1,  1000)
async def gf(name):
    logger.debug(f"invoke gf({name}) at {time.time()}")
    await asyncio.sleep(3)  # 这里用asyncio的sleep代替耗时操作，也可以是实际的网络等待、文件读写等耗时操作
    return name

@app.route('/get-sync-1', methods=['GET'])
def hello2():
    logger.debug(f"global_variable:{global_variable}, sync-1 api {time.time()}")
    # 以下调用方式有Bug：RuntimeWarning: coroutine 'gf' was never awaited
    gf("first")
    gf("second")
    return f'Hello2, World! {time.time()}'

# 这种写法没有提交到事件循环是同步的
@app.route('/get-sync-2', methods=['GET'])
async def hello():
    worker_pid = os.getpid()  # 获取当前worker的PID
    logger.debug(f"global_variable:{global_variable}, sync-2 api {time.time()} by worker PID:{worker_pid}")
    await gf("first") # 模拟异步操作
    await gf("second")  # 模拟异步操作
    logger.debug('second wait done')
    return f'Hello, World! {time.time()}'

async def async_fuc():
    worker_pid = os.getpid()  # 获取当前worker的PID
    logger.debug('async_fuc start')
    await asyncio.sleep(2)  # 模拟异步操作
    logger.debug('async_fuc wait done')
    return 'async_fuc done'

@app.route('/get-async', methods=['GET'])
async def getasync():
    worker_pid = os.getpid()  # 获取当前worker的PID
    logger.debug(f"global_variable:{global_variable}, async api {time.time()} by worker PID:{worker_pid}")
    task1 = asyncio.create_task(async_fuc())
    task2 = asyncio.create_task(async_fuc())
    await asyncio.gather(task1, task2)
    return jsonify(data='result'), 200

@app.route('/get3', methods=['GET'])
def get3():
    worker_pid = os.getpid()  # 获取当前worker的PID
    logger.debug(f"hello2 api {time.time()} by worker PID:{worker_pid}")
    time.sleep(3)
    return f'Hello2, World! {time.time()} by worker PID:{worker_pid}'
# async def 所有请求都在 同一个事件循环线程 中处理（通过协程切换）
@app.route('/get2', methods=['GET'])
async def get2():
    worker_pid = os.getpid()  # 获取当前worker的PID
    logger.debug(f"hello2 api {time.time()} by worker PID:{worker_pid}")
    time.sleep(3)
    return f'Hello2, World! {time.time()} by worker PID:{worker_pid}'

@app.route('/get', methods=['GET'])
async def get():
    worker_pid = os.getpid()  # 获取当前worker的PID
    logger.debug(f"hello api {time.time()} by worker PID:{worker_pid}")
    await asyncio.sleep(3)
    return f'Hello, World! {time.time()} by worker PID:{worker_pid}'
# 即使对于异步视图，每个请求仍然会绑定一个 worker。好处是您可以在一个视图内运行异步代码，例如多个并发数据库查询，对外部 API 的 HTTP 请求，等等。
# 但是，您的应用程序可以处理的请求并发数量将保持不变。
# 可以使用如下方式启动:
# hypercorn flask_async_web:app --bind 0.0.0.0:5600 -w 1 -k asyncio
# gunicorn --workers 1 --threads 1 --timeout 0 --bind 0.0.0.0:5600 flask_async_web:app
# gunicorn -c gunicorn_config_4_flask_async_web.py flask_async_web:app
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5600)
    # import uvicorn
    # uvicorn.run(asgi_app, host="127.0.0.1", port=5600)   # ASGI 'lifespan' protocol appears unsupported.